package com.teamone.mobilewatch.accessor.webservice;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;

import com.teamone.mobilewatch.accessor.BackendException;

/**
 * Handles HTTP requests
 */
public class HttpRequester {

	public static int TIMEOUT = 20 * 1000;
	private static HttpClient httpClient = null;

	/**
	 * Initializes and returns HTTPClient instance
	 */
	private static HttpClient getHttpClient() {
		if (httpClient == null) {
			// initialize http client
			httpClient = new DefaultHttpClient();
			httpClient.getParams().setIntParameter(
					CoreConnectionPNames.CONNECTION_TIMEOUT, TIMEOUT);
			httpClient.getParams().setIntParameter(
					CoreConnectionPNames.SO_TIMEOUT, TIMEOUT);
		}

		return httpClient;
	}

	/**
	 * Sends HTTP GET request and returns the response
	 * 
	 * @param requestUri
	 * @return
	 */
	public static String sendGetRequest(String requestUri) {
		String response = null;
		try {
			HttpClient httpClient = getHttpClient();
			HttpUriRequest httpUriRequest = new HttpGet(requestUri);
			HttpResponse httpResponse = httpClient.execute(httpUriRequest);
			response = processHttpResponse(httpResponse);
		} catch (BackendException e) {
			new BackendException(e.getMessage(), e.getCode());
		} catch (IOException e) {
			new BackendException(e.getMessage(), BackendException.IO_EXCEPTION);
		} catch (Exception e) {
			new BackendException(e.getMessage(), BackendException.ERROR);
		}

		return response;
	}

	/**
	 * Sends HTTP POST request with name/value params and returns the response
	 * 
	 * @param requestUri
	 *            - request URI string
	 * @param params
	 *            - HashMap of paramName, paramValue pairs
	 * @return response string
	 * @throws BackendException
	 */
	public static String sendPostRequest(String requestUri,
			HashMap<String, String> params) throws BackendException {
		String response = null;
		try {
			HttpClient httpClient = getHttpClient();
			HttpUriRequest httpUriRequest = new HttpPost(requestUri);

			// add params if any
			if (params != null) {
				List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(
						params.size());
				// read name/value from the map and append them to the HHTP POST
				// request
				for (Map.Entry<String, String> entry : params.entrySet()) {
					String name = entry.getKey();
					String value = entry.getValue();
					nameValuePairs.add(new BasicNameValuePair(name, value));
				}

				((HttpPost) httpUriRequest).setEntity(new UrlEncodedFormEntity(
						nameValuePairs));
			}

			HttpResponse httpResponse = httpClient.execute(httpUriRequest);
			response = processHttpResponse(httpResponse);
		} catch (BackendException e) {
			throw new BackendException(e.getMessage(), e.getCode());
		} catch (IOException e) {
			throw new BackendException(e.getMessage(),
					BackendException.IO_EXCEPTION);
		} catch (Exception e) {
			throw new BackendException(e.getMessage(), BackendException.ERROR);
		}

		return response;
	}

	/**
	 * Reads response from HTTP response object and returns it as a string
	 * 
	 * @param httpResponse
	 * @return processed response string
	 * @throws IOException
	 * @throws BackendException
	 * @throws UnsupportedEncodingException
	 */
	private static String processHttpResponse(HttpResponse httpResponse)
			throws IOException, BackendException, UnsupportedEncodingException {
		String response = null;
		if(httpResponse.getStatusLine().getStatusCode() != 200){
			throw new BackendException("Server is unavailable...["+ httpResponse.getStatusLine().getStatusCode()+"]",
					BackendException.BAD_RESPONSE);
		}
		
		BufferedInputStream bufferedInputStream = new BufferedInputStream(
				httpResponse.getEntity().getContent());
		int contentLength = (int) httpResponse.getEntity().getContentLength();
		if (contentLength <= 0) {
			throw new BackendException("Response length = 0",
					BackendException.BAD_RESPONSE);
		} else {
			byte[] bytes = new byte[contentLength];
			bufferedInputStream.read(bytes);
			bufferedInputStream.close();
			response = new String(bytes, "utf-8");
			response = response.replaceAll("&lt;", "<");
			response = response.replaceAll("&gt;", ">");
		}
		return response;
	}

}
